package org.harsh.transmission.common.codec;

import com.ruoyi.system.service.ISysDeptService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.harsh.common.Config;
import org.harsh.common.crypt.AesCrypt;
import org.harsh.dispatch.CommVars;
import org.harsh.transmission.common.NodeItem;
import org.harsh.transmission.common.NodeQueue;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.List;

@Slf4j
@Component
public class CryptMsgPackCodec extends MessageToMessageCodec<ByteBuf, ByteBuf> {
    //todo 对于重连接，会出现解密出错的问题
    @Override
    protected void encode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception {
        byte[] data = new byte[buf.readableBytes()];
        buf.getBytes(buf.readerIndex(), data);
        InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();
        String peerAddr = address.getAddress().getHostAddress();
        NodeItem item = NodeQueue.get(peerAddr);
        if(item == null) {
            //throw new Exception("Secret Key is null.");
            log.info("Share key does not exist.");
            byte[] sharedKey = Config.DEFAULT_KEY.getBytes(Config.DEFAULT_CHARSET);
            AesCrypt crypt = new AesCrypt(sharedKey);
            crypt.init();
            byte[] cryptData = crypt.encrypt(data);
            list.add(Unpooled.copiedBuffer(cryptData));
        } else {
            byte[] sharedKey = item.getSharedKey();
            AesCrypt crypt = new AesCrypt(sharedKey);
            crypt.init();
            byte[] cryptData = crypt.encrypt(data);
            list.add(Unpooled.copiedBuffer(cryptData));
        }
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> list) throws Exception {
        byte[] data = new byte[buf.readableBytes()];
        buf.readBytes(data);
        InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();
        String peerAddr = address.getAddress().getHostAddress();
        NodeItem item = NodeQueue.get(peerAddr);
        if(item == null) {
            log.info("Share key does not exist.");
            byte[] sharedKey = Config.DEFAULT_KEY.getBytes(Config.DEFAULT_CHARSET);
            AesCrypt crypt = new AesCrypt(sharedKey);
            crypt.init();
            byte[] cryptData = crypt.decrypt(data);
            list.add(Unpooled.copiedBuffer(cryptData));
        } else {
            byte[] sharedKey = item.getSharedKey();
            AesCrypt crypt = new AesCrypt(sharedKey);
            crypt.init();
            byte[] cryptData = crypt.decrypt(data);
            list.add(Unpooled.copiedBuffer(cryptData));
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();
        String peerAddr = address.getAddress().getHostAddress();
        log.error("【Channel】{}-peerAddr:{}加解密出错，ErrMsg:{}", ctx.channel().id(), peerAddr, cause.getLocalizedMessage());
        //加解密出错，直接关闭通道，重新连接
        NodeQueue.remove(peerAddr);
        ctx.channel().close().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                CommVars.removeChannel(peerAddr);
            }
        });


        // todo 此处需要考虑等到一段时间后重新发起建立连接
    }
}
